﻿//Author:Michal Sporna
//License: https://operationsneakpeek.codeplex.com/license

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using System.Threading;
using Util;
using Microsoft.Xna.Framework.Graphics;

namespace Characters
{
    /// <summary>
    /// NPC
    /// can be anyone: enemy, friend, npc
    /// </summary>
    public class NPC
    {
       

        #region properties
        public int UniqueID;//unique ID 
        public string ID;
        public Util.Helpers.PublicEnums.NPCType NPCType;
        public List<Helpers.NPCTexture> Textures;
        public int Width;
        public int Height;
        public int Step;//how fast the character can go?
        public List<Helpers.MovePattern> MovePatterns;
        public string WeaponID;
        //public List<Levels.MapCellInfo> PartIDs; //where the npc can occur
        public string Map;
        public List<Util.Classes.Event> Events; //list of events associated with the NPC
       

        //statistics
        public int Strength;
        public int Perception;
        public int Luck;
        public int IQ;
        public string SpecialAbilityID;
        public int Health;

        //misc
        public Util.Helpers.PublicEnums.NPCState CurrentState;


        #endregion

        #region public fields
        //helpers
        
        public int CurrentPosX;
        public int CurrentPosY;
        public string NPCTypeString;
        public int MovePatternCt;
        public bool HeatDrawn;//set to true, if heat rect is already drawn
        public bool IsDistracting;
        #endregion

        #region private fields
        private bool _MovePatternBeingUpdated;
        //current texture
        private Texture2D _CurrentTexture;
        private bool _AvatarSpotted;
        private int _WhichFOVRectSpottedAvatar;
        //Flags used in move patterns: if x/y is reached by npc, then set to true
        private bool _XReached;
        private bool _YReached;

        #region textures
        private Texture2D _CircleTexture;
        private bool _CircleTextureSet;

        #endregion


        #region distraction control
        private int[] _DistractionControlRect;
       
        #endregion


        /// <summary>
        /// field of view consists of 3 rectangles
        /// big, medium and small
        /// </summary>
        #region fov rectangles
        private int[] _FieldOfViewRect1;
        private int[] _FieldOfViewRect2;
        private int[] _FieldOfViewRect3;
        #endregion


        private int _FieldOfViewCT;
        private double _ElapsedMs2; //where Ms=miliseconds
        private double _ElapsedMs1;
        private double _ElapsedMs3;
        private double _ElapsedMs4; //after the heat
        private bool _IsWaiting; //if true, then NPC is idling (waiting)
        private bool _IsFieldOfViewTimed; //if true, then field of view lasts in some position only x amount of time
        private int _CurrentFieldOfVIewTime; //how long current FOV lasts
        private bool _InTheMiddleOfShooting;
        private int _stepBeforeStop; //value of the step from XML
        //after the heat
        private bool _IsHeatCooling; //after heat is gone, npc waits x seconds before resuming a patrol
        private bool _DrawCircle1;
        private bool _DrawCircle2;
        private bool _DrawCircle3;
        private bool _Circle1Drawn;
        private bool _Circle2Drawn;
        private bool _Circle3Drawn;
        #endregion



        #region methods

        /// <summary>
        /// Default constructor
        /// </summary>
        public NPC()
        {
            try
            {

                ID = string.Empty;
                NPCType = Util.Helpers.PublicEnums.NPCType.neutral;
                Textures = new List<Helpers.NPCTexture>();
                CurrentPosX = 0;
                CurrentPosY = 0;
                Width = 0;
                Height = 0;
                Step = 0;
                MovePatterns = new List<Helpers.MovePattern>();
                WeaponID = string.Empty;
                Strength = 0;
                Perception = 0;
                Luck = 0;
                IQ = 0;
                SpecialAbilityID = string.Empty;
                Health = 0;
                Events = new List<Util.Classes.Event>();
                //PartIDs = new List<Levels.MapCellInfo>();
                //_FieldOfViewWidth = this.Width * 3;
                _WhichFOVRectSpottedAvatar = 0;
                IsDistracting = false;

                //helpers
                MovePatternCt = 0;
                _FieldOfViewCT = 0;
                _AvatarSpotted = false;
                _FieldOfViewRect1 = null;
                _FieldOfViewRect2 = null;
                _FieldOfViewRect3 = null;
                CurrentState = Util.Helpers.PublicEnums.NPCState.Walking;
                _IsWaiting = false;
                _DistractionControlRect = null;

            }
            catch (Exception ex)
            {
                Util.ErrorLogging.LogError(ex);
                return;
            }


        }


        /// <summary>
        /// After NPC is loaded from XML
        /// string values need to be converted into numeric values, enums etc.
        /// </summary>
        public void DoConversions()
        {
            try
            {
                //npc type
                switch (NPCTypeString)
                {
                    case "Hostile":
                        {
                            this.NPCType = Util.Helpers.PublicEnums.NPCType.hostile;
                            break;
                        }
                    case "Story":
                        {
                            this.NPCType = Util.Helpers.PublicEnums.NPCType.story;
                            break;
                        }
                    case "Neutral":
                        {
                            this.NPCType = Util.Helpers.PublicEnums.NPCType.neutral;
                            break;
                        }
                }

                


                #region parameters of the events

                for (int i = 0; i < this.Events.Count; i++)
                {
                    //Event
                    #region event type

                    switch (this.Events[i].EventTypeString)
                    {
                        case "onAvatarSpotted":
                            {
                                this.Events[i].EventType = Util.Helpers.PublicEnums.EventType.onAvatarSpotted;
                                this.Events[i].EventTypeString = null;
                                break;
                            }
                    }



                    #endregion


                    //fpreach param
                    for (int i1 = 0; i1 < this.Events[i].Parameters.Count; i1++)
                    {
                        switch (this.Events[i].Parameters[i1].ParameterString)
                        {
                            case "this":
                                {
                                    this.Events[i].Parameters[i1].Parameter = this;
                                    //this.Events[i].Parameters[i1].ParameterString = null;

                                    break;
                                }

                        }
                    }
                }


                #endregion

                //assign current pos x,y 
                //this.CurrentPosX = MovePatterns[0].StartX;
                //this.CurrentPosY = MovePatterns[0].StartY;

                //cleanup
                NPCTypeString = null;

                //npc texture type
                for (int i = 0; i < this.Textures.Count; i++)
                {
                    switch (this.Textures[i].TextureTypeString)
                    {
                        case "Walk1":
                            {
                                this.Textures[i].TextureType = Util.Helpers.PublicEnums.NPCTextureType.Walk;
                                break;
                            }
                        case "Attack":
                            {
                                this.Textures[i].TextureType = Util.Helpers.PublicEnums.NPCTextureType.Attack;

                                break;
                            }
                        case "Attack1":
                            {
                                this.Textures[i].TextureType = Util.Helpers.PublicEnums.NPCTextureType.Attack1;

                                break;
                            }
                    }

                    //cleanup
                    this.Textures[i].TextureTypeString = null;
                }

            
            }
            catch (Exception ex)
            {
                Util.ErrorLogging.LogError(ex);
                return;
            }


        }

       

        #region updating and drawing



        /// <summary>
        /// Move NPC according to his move patterns
        /// </summary>
        public void MoveNPC()
        {
            
         

            try
            {
                //draw only if current map cell is the map cell where npc is set to appear
                //if (!Util.Helpers.Utilities.ListContainsMapCell(Levels.LevelManager.CurrentMap.CurrentMapCell.ID,this.PartIDs))
                //{
                //    return;
                //}

              

                if (this.CurrentState == Util.Helpers.PublicEnums.NPCState.Walking)
                {
                    #region walking

                    ////if current position is past move patterns boundries, then change move pattern to the next one
                    //if (MovePatternCt > MovePatterns.Count - 1)
                    //{
                    //    MovePatternCt = 0;
                    //    _FieldOfViewCT = 0;
                    //    //reset position
                    //    CurrentPosX = MovePatterns[MovePatternCt].StartX;
                    //    CurrentPosY = MovePatterns[MovePatternCt].StartY;
                    //}

                    #region heat is cooling

                    //if heat is cooling ,and not distracting
                    if (_IsHeatCooling)
                    {
                        if (!IsDistracting)
                        {
                            if (!_Circle1Drawn)
                            {
                                if (Cache.GameTime.TotalGameTime.TotalMilliseconds - _ElapsedMs4 > 1000)
                                {
                                    _DrawCircle1 = true;
                                    return;
                                }
                            }

                            if (!_Circle2Drawn)
                            {
                                if (Cache.GameTime.TotalGameTime.TotalMilliseconds - _ElapsedMs4 > 1000)
                                {
                                    _DrawCircle2 = true;
                                    return;
                                }
                            }

                            if (!_Circle3Drawn)
                            {
                                if (Cache.GameTime.TotalGameTime.TotalMilliseconds - _ElapsedMs4 > 1000)
                                {
                                    _DrawCircle3 = true;
                                    return;
                                }
                            }


                            if (_Circle1Drawn && _Circle2Drawn && _Circle3Drawn)
                            {
                                //return to normal patroling
                                _IsHeatCooling = false;
                                this.Step = this._stepBeforeStop; //restore regular step value
                                _stepBeforeStop = 0;
                                //reset circles flags
                                _DrawCircle1 = false;
                                _DrawCircle2 = false;
                                _DrawCircle3 = false;
                                _Circle1Drawn = false;
                                _Circle2Drawn = false;
                                _Circle3Drawn = false;

                            }
                        }
                        else
                        {
                            //just fool the system and mark heat cooling as done
                            //even though it was not drawn
                            //return to normal patroling
                            _IsHeatCooling = false;
                            this.Step = this._stepBeforeStop; //restore regular step value
                            _stepBeforeStop = 0;
                            //reset circles flags
                            _DrawCircle1 = false;
                            _DrawCircle2 = false;
                            _DrawCircle3 = false;
                            _Circle1Drawn = false;
                            _Circle2Drawn = false;
                            _Circle3Drawn = false;
                        }
                    }


                    #endregion



                    //reset heat drawn flag
                    HeatDrawn = false;
                    World.WorldManager.IsHeatActive = false;


                    if (MovePatterns[MovePatternCt].IsMoving)
                    {

                        #region move npc (only if IsMoving is set to true)



                        switch (MovePatterns[MovePatternCt].MoveDirection)
                        {
                            case Util.Helpers.PublicEnums.NPCMoveDirection.None:
                                {
                                    #region idle
                                    ////idle
                                   // _CurrentTexture = _GetTextureNameByType(Util.Helpers.PublicEnums.NPCTextureType.Walk);

                                    ////update x coordinate as npc is moving right
                                    //if (!_IsWaiting)
                                    //{
                                    //    CurrentPosX += 0; //+0 
                                    //}

                                    //prepare field of view
                                    _PrepareFieldOfView();

                                    #endregion

                                    break;

                                }
                            case Util.Helpers.PublicEnums.NPCMoveDirection.right:
                                {
                                    #region right

                                    //_CurrentTexture = _GetTextureNameByType(Util.Helpers.PublicEnums.NPCTextureType.Walk);

                                    //update x coordinate as npc is moving right
                                    if (!_IsWaiting && !IsDistracting)
                                    {
                                        CurrentPosX += Step;
                                    }

                                    //prepare field of view
                                    _PrepareFieldOfView();

                                    #endregion

                                    break;
                                }
                            case Util.Helpers.PublicEnums.NPCMoveDirection.left:
                                {

                                    #region left

                                    //_CurrentTexture = _GetTextureNameByType(Util.Helpers.PublicEnums.NPCTextureType.Walk);

                                    //update x coordinate as npc is moving right
                                    if (!_IsWaiting && !IsDistracting)
                                    {
                                        CurrentPosX -= Step;
                                    }



                                    //prepare field of view
                                    _PrepareFieldOfView();

                                    #endregion

                                    break;
                                }
                            case Util.Helpers.PublicEnums.NPCMoveDirection.up:
                                {

                                    #region up

                                    //_CurrentTexture = _GetTextureNameByType(Util.Helpers.PublicEnums.NPCTextureType.Walk);

                                    //update x coordinate as npc is moving right
                                    if (!_IsWaiting && !IsDistracting)
                                    {
                                        CurrentPosY -= Step;
                                    }

                                    //prepare field of view
                                    _PrepareFieldOfView();

                                    #endregion

                                    break;
                                }
                            case Util.Helpers.PublicEnums.NPCMoveDirection.down:
                                {

                                    #region down

                                   // _CurrentTexture = _GetTextureNameByType(Util.Helpers.PublicEnums.NPCTextureType.Walk);

                                    //update x coordinate as npc is moving right
                                    if (!_IsWaiting && !IsDistracting)
                                    {
                                        CurrentPosY += Step;
                                    }

                                    //prepare field of view
                                    _PrepareFieldOfView();

                                    #endregion

                                    break;
                                }
                            case Util.Helpers.PublicEnums.NPCMoveDirection.crossUpLeft:
                                {

                                    #region cross up left

                                   // _CurrentTexture = _GetTextureNameByType(Util.Helpers.PublicEnums.NPCTextureType.Walk);

                                    //update x coordinate as npc is moving right
                                    if (!_IsWaiting && !IsDistracting)
                                    {
                                        CurrentPosY -= Step;
                                        CurrentPosX -= Step;
                                    }

                                    //prepare field of view
                                    _PrepareFieldOfView();

                                    #endregion

                                    break;
                                }
                            case Util.Helpers.PublicEnums.NPCMoveDirection.CrossUpRight:
                                {

                                    #region cross up right

                                    //_CurrentTexture = _GetTextureNameByType(Util.Helpers.PublicEnums.NPCTextureType.Walk);

                                    //update x coordinate as npc is moving right
                                    if (!_IsWaiting && !IsDistracting)
                                    {
                                        CurrentPosY -= Step;
                                        CurrentPosX += Step;
                                    }

                                    //prepare field of view
                                    _PrepareFieldOfView();

                                    #endregion

                                    break;
                                }
                            case Util.Helpers.PublicEnums.NPCMoveDirection.crossDownRight:
                                {

                                    #region cross down right

                                    //_CurrentTexture = _GetTextureNameByType(Util.Helpers.PublicEnums.NPCTextureType.Walk);

                                    //update x coordinate as npc is moving right
                                    if (!_IsWaiting && !IsDistracting)
                                    {
                                        CurrentPosY += Step;
                                        CurrentPosX += Step;
                                    }

                                    //prepare field of view
                                    _PrepareFieldOfView();

                                    #endregion

                                    break;
                                }
                            case Util.Helpers.PublicEnums.NPCMoveDirection.crossDownLeft:
                                {

                                    #region cross down left

                                    //_CurrentTexture = _GetTextureNameByType(Util.Helpers.PublicEnums.NPCTextureType.Walk);

                                    //update x coordinate as npc is moving right
                                    if (!_IsWaiting && !IsDistracting)
                                    {
                                        CurrentPosY += Step;
                                        CurrentPosX -= Step;
                                    }

                                    //prepare field of view
                                    _PrepareFieldOfView();

                                    #endregion

                                    break;
                                }
                        }


                        _CurrentTexture = _GetTextureInstanceByType(Util.Helpers.PublicEnums.NPCTextureType.Walk);

                        #endregion

                    }
                    else
                    {
                        //set XReached and YReached to true as npc is not moving (flag is set to false intentionally)
                        _XReached = true;
                        _YReached = true;

                        //texture
                        _CurrentTexture = _GetTextureInstanceByType(Util.Helpers.PublicEnums.NPCTextureType.Walk);
                        //prepare field of view
                        _PrepareFieldOfView();

                        //if (this.IsDistracting)
                        //{
                        //    //is waiting, wait x amount of time
                        //    if (Util.Cache.GameTime.TotalGameTime.TotalMilliseconds - _ElapsedMs1 >= MovePatterns[MovePatternCt].WaitTime)
                        //    {
                        //        //stop waiting
                        //        _IsWaiting = false;
                        //        _ElapsedMs1 = 0;
                        //        ExitDistractingMode();
                        //        return;
                        //    }

                        //}

                    }

                    //detect avatar -moved to drawFOV
                    //_DetectAvatar();

                    //see if npc reached Y or X from move pattern
                    if (!_XReached)
                    {
                        if (this.CurrentPosX == MovePatterns[MovePatternCt].EndX)
                        {
                            _XReached = true;
                        }
                    }
                    //Y:
                    if (!_YReached)
                    {
                        if (this.CurrentPosY == MovePatterns[MovePatternCt].EndY)
                        {
                            _YReached = true;
                        }
                    }

                    //change move pattern
                    //if (this.CurrentPosX == MovePatterns[MovePatternCt].EndX && this.CurrentPosY == MovePatterns[MovePatternCt].EndY)
                    if(_XReached&&_YReached)
                    {
                        #region npc is waiting
                        //wait specific period of time
                        if (!_IsWaiting)
                        {
                            if (MovePatterns[MovePatternCt].WaitTime > 0)
                            {
                                //save current elapsed milliseconds
                                _ElapsedMs1 = Util.Cache.GameTime.TotalGameTime.TotalMilliseconds;
                                _IsWaiting = true;
                            }

                        }
                        else
                        {
                            //is waiting, wait x amount of time
                            if (Util.Cache.GameTime.TotalGameTime.TotalMilliseconds - _ElapsedMs1 >= MovePatterns[MovePatternCt].WaitTime)
                            {
                                //stop waiting
                                _IsWaiting = false;
                                _ElapsedMs1 = 0;
                            }


                        }
                        #endregion

                        //go further, to the next move pattern only if npc is not waiting
                        if (!_IsWaiting)
                        {

                            //move pattern is changing, so reset WellHiddenAcheivementDoneAlready flag
                            //MovePatterns[MovePatternCt].WellHiddenAcheivementDoneAlready = false; //31.12.2012 obsolete!!!!!

                            //set current move pattern to the next one
                            //if current position is past move patterns boundries, then change move pattern to the next one

                            if (!IsDistracting) //if not distracting do it regular way
                            {
                                _UpdateMovePattern();
                            }
                            else
                            {
                                //if is distracting
                                //exit distracting mode now, restore current move pattern and current fov
                                this.ExitDistractingMode();

                            }



                            //MovePatternCt += 1;
                            //_FieldOfViewCT = 0;

                            //if (MovePatternCt <= MovePatterns.Count - 1)
                            //{

                            //    CurrentPosX = MovePatterns[MovePatternCt].StartX;
                            //    CurrentPosY = MovePatterns[MovePatternCt].StartY;
                            //}
                        }


                       
                    }

                    #endregion

                }
                else if (this.CurrentState == Util.Helpers.PublicEnums.NPCState.Attacking)
                {
                    #region ATTACKING

                    if (!HeatDrawn)
                    {
                      

                        return;
                    }

                    //if avatar is far away from the npc, the stop shooting
                    if (!_IsAvatarAwayFromHeat() && !_IsAvatarHiddenBehindObstacle())
                    {
                        //hurt avatar
                       
                        //exit throwing mode
                        if (!World.WorldManager.ThrowComplete)
                        {
                            World.WorldManager.ExitThrowingMode();
                        }

                        if (!_InTheMiddleOfShooting)
                        {
                            //Util.Cache.Avatar.HurtAvatar(5);
                            _ElapsedMs3 = Cache.GameTime.TotalGameTime.TotalMilliseconds;
                            _InTheMiddleOfShooting = true;
                        }

                        _CurrentTexture = _GetTextureInstanceByType(Util.Helpers.PublicEnums.NPCTextureType.Attack) ;

                        //if 1 second elapsed,shoot again
                        if (Cache.GameTime.TotalGameTime.TotalMilliseconds-_ElapsedMs3 >= 1000)
                        {
                            Util.Cache.Avatar.HurtAvatar(Strength);
                            _InTheMiddleOfShooting = false;
                            //show animation of shooting
                            _CurrentTexture = _GetTextureInstanceByType(Util.Helpers.PublicEnums.NPCTextureType.Attack1);
                        }


                       



                    }
                    else
                    {


                        
                            _IsHeatCooling = true;
                            HeatDrawn = false;
                            World.WorldManager.IsHeatActive = false;
                            _ElapsedMs4 = Cache.GameTime.TotalGameTime.TotalMilliseconds;
                            _AvatarSpotted = false;
                            this.CurrentState = Util.Helpers.PublicEnums.NPCState.Walking;

                            if (IsDistracting)
                            {
                                this.ExitDistractingMode();
                            }

                       //return to regular move pattern
                        //this.CurrentState = Util.Helpers.PublicEnums.NPCState.Walking;
                        //this.Step = this._stepBeforeStop; //restore regular step value
                        //_stepBeforeStop = 0;
                        //_AvatarSpotted = false;
                        //HeatDrawn = false;
                        //World.WorldManager.IsHeatActive = false;
                    }

                    #endregion


                }
               
               
                

            }
            catch (Exception ex)
            {
                Util.ErrorLogging.LogError(ex);
                return;
            }



        }


        

        /// <summary>
        /// Draw npc
        /// </summary>
        public void Draw()
        {
            //declare
            int[] npcRect;

            try
            {
                //if heat is on, and npc is not attacking but in heat zone
                //then do not draw it
                if (World.WorldManager.IsHeatActive && !this.HeatDrawn)
                {
                    npcRect = new int[]{CurrentPosX, CurrentPosY, Width, Height};

                    if (World.WorldManager.HeatRectangle != null)
                    {
                        if (World.WorldManager.IsObstacleTouched(World.WorldManager.HeatRectangle, npcRect))
                        {
                            //then return, do not draw this npc
                            return;
                        }
                    }

                }


                //draw npc only if current map cell is the same as npc is supposed to be on
                //if (!Util.Helpers.Utilities.ListContainsMapCell(Levels.LevelManager.CurrentMap.CurrentMapCell.ID, this.PartIDs))
                //{
                //    return;
                //}

                if (this.CurrentState == Util.Helpers.PublicEnums.NPCState.Walking)
                {
                    #region walking
                    //draw
                    if (_CurrentTexture != null)
                    {
                        if (IsDistracting)
                        {
                            //draw npc distracted icon
                            Util.Cache.Draw(Util.Cache.GetTexture("NpcDistractedIcon").Text2D, new Rectangle(CurrentPosX, CurrentPosY - this.Height / 2, this.Width, this.Height), Color.White);
                        }
                        else
                        {
                            //perception field
                            if (_DistractionControlRect != null)
                            {
                                Util.Cache.Draw(Util.Cache.GetTexture("inventorySlot").Text2D, _DistractionControlRect, Color.White);
                            }
                        }

                        Util.Cache.Draw(_CurrentTexture, new int[]{CurrentPosX, CurrentPosY, Width, Height}, Color.White);
                        //draw field of view
                        _DrawFieldOfView();

                        
                    }
                    #endregion
                }
                else if (this.CurrentState == Util.Helpers.PublicEnums.NPCState.Attacking)
                {
                    #region attacking
                
                    //set current texture-npc attacking...
                    //_CurrentTexture = "npc2";
                    //draw
                    Util.Cache.Draw(_CurrentTexture, new int[]{CurrentPosX, CurrentPosY, Width, Height}, Color.White);

                    if (!_IsHeatCooling)
                    {
                        _DrawHeat();
                    }


                    //if 3 seconds elapsed, then show game over screen
                    //if (Cache.GameTime.TotalGameTime.TotalMilliseconds-_ElapsedMs1 >= 2000)
                    //{
                    //    Cache.CurrentScreen = Cache.Screen.GameOver;
                    //}


                    #endregion
                }

            }
            catch (Exception ex)
            {
                Util.ErrorLogging.LogError(ex);
                return;
            }
        }


        /// <summary>
        /// Prepare distraction control
        /// which is invisible rectangle that notices when
        /// item was thrown nearby
        /// if yes,then npc is distracted
        /// </summary>
        public void PrepareDistractionControl()
        {
            //declare
            Rectangle npcRect;

            try
            {
                //create distraction control rectangle,
                //only if npc is in reach of throw field
                //if not, then no need to create distraction rect as this npc cannot be distracted

                if (World.WorldManager.DrawThrowFieldOfReachFlag)
                {
                    npcRect = new Rectangle(this.CurrentPosX, this.CurrentPosY, this.Width, this.Height);

                    if (npcRect.Intersects(World.WorldManager.FieldOfThrowReachRect))
                    {
                        this._DistractionControlRect = new int[]{(int)(this.CurrentPosX - ((this.Perception * 10) / 2)), (int)(this.CurrentPosY - ((this.Perception * 10) / 2)), (int)this.Perception * 10 + this.Width, (int)this.Perception * 10 + this.Height};
                        //this._DistractionControlRect = new Rectangle((int)(this.CurrentPosX - (_FieldOfViewRect1.Width + _FieldOfViewRect2.Width + _FieldOfViewRect3.Width)), (int)(this.CurrentPosY - (_FieldOfViewRect1.Height + _FieldOfViewRect2.Height + _FieldOfViewRect3.Height)), (int)(_FieldOfViewRect1.Width + _FieldOfViewRect2.Width + _FieldOfViewRect3.Width) * 2 + this.Width, (_FieldOfViewRect1.Height + _FieldOfViewRect2.Height + _FieldOfViewRect3.Height) * 2 + this.Height);
                        //add to the list of npcs to distract
                        World.WorldManager.NPCToDistract.Add(this);

                    }
                    else
                    {
                        //if npc is no longer in a reach of throw
                        //then remove from npc to distract
                        for (int i = 0; i < World.WorldManager.NPCToDistract.Count; i++)
                        {
                            if (World.WorldManager.NPCToDistract[i].UniqueID == this.UniqueID)
                            {
                                World.WorldManager.NPCToDistract.RemoveAt(i);
                                break;
                            }
                        }
                    }
                }


            }
            catch (Exception ex)
            {
                Util.ErrorLogging.LogError(ex);
                return;
            }
        }

        /// <summary>
        /// clear distraction control
        /// </summary>
        public void ClearDistractionControl()
        {
            try
            {
                _DistractionControlRect = null;

               
           
            }
            catch (Exception ex)
            {
                Util.ErrorLogging.LogError(ex);
                return;
            }


        }

        /// <summary>
        /// quit distracting
        /// </summary>
        public void ExitDistractingMode()
        {
            try
            {
                for (int i = 0; i < World.WorldManager.StoredFOVs.Count; i++)
                {
                    if (World.WorldManager.StoredFOVs[i].NPCID == this.UniqueID)
                    {
                        //restore move pattern that is next or reset if no move pattern after that
                        MovePatternCt = World.WorldManager.StoredFOVs[i].CurrentMovePatternCt;

                        #region restore move pattern
                        MovePatterns[MovePatternCt].EndX = World.WorldManager.StoredFOVs[i].CurrentMovePattern.EndX;
                        MovePatterns[MovePatternCt].EndY = World.WorldManager.StoredFOVs[i].CurrentMovePattern.EndY;
                        MovePatterns[MovePatternCt].FieldsOfView = World.WorldManager.StoredFOVs[i].CurrentMovePattern.FieldsOfView;
                        MovePatterns[MovePatternCt].MoveDirection = World.WorldManager.StoredFOVs[i].CurrentMovePattern.MoveDirection;
                        MovePatterns[MovePatternCt].NPCCT = World.WorldManager.StoredFOVs[i].CurrentMovePattern.NPCCT;
                        MovePatterns[MovePatternCt].NPCID = World.WorldManager.StoredFOVs[i].CurrentMovePattern.NPCID;
                        MovePatterns[MovePatternCt].StartX = World.WorldManager.StoredFOVs[i].CurrentMovePattern.StartX;
                        MovePatterns[MovePatternCt].StartY = World.WorldManager.StoredFOVs[i].CurrentMovePattern.StartY;
                        MovePatterns[MovePatternCt].WaitTime = World.WorldManager.StoredFOVs[i].CurrentMovePattern.WaitTime;
                        MovePatterns[MovePatternCt].IsMoving = World.WorldManager.StoredFOVs[i].IsMoving;
                        

                        #endregion



                        _FieldOfViewCT = World.WorldManager.StoredFOVs[i].CurrentFov;
                        _IsFieldOfViewTimed = World.WorldManager.StoredFOVs[i].IsCurrentFovTimed;
                        _YReached = World.WorldManager.StoredFOVs[i].YReached;
                        _XReached = World.WorldManager.StoredFOVs[i].XReached;


                        //restore fov
                        for (int i1 = 0; i1 < MovePatterns[MovePatternCt].FieldsOfView.Count; i1++)
                        {
                            //if current field of view, then modify
                            if (MovePatterns[MovePatternCt].FieldsOfView[i1].OrderNumber == _FieldOfViewCT)
                            {
                                //restore fov
                                #region restore fov
                                MovePatterns[MovePatternCt].FieldsOfView[i].Circles = World.WorldManager.StoredFOVs[i].Fov.Circles;
                                MovePatterns[MovePatternCt].FieldsOfView[i].Direction = World.WorldManager.StoredFOVs[i].Fov.Direction;
                                MovePatterns[MovePatternCt].FieldsOfView[i].OrderNumber = World.WorldManager.StoredFOVs[i].Fov.OrderNumber;
                                MovePatterns[MovePatternCt].FieldsOfView[i].Time = World.WorldManager.StoredFOVs[i].Fov.Time;


                                #endregion

                                break;
                            }
                        }

                        //if fov was timed, then set timer to now
                        //to restart it
                        //restore FOV
                        if (_IsFieldOfViewTimed)
                        {
                            //set elapsed time to now
                            _ElapsedMs2 = Util.Cache.GameTime.TotalGameTime.TotalMilliseconds;

                        }

                        //set is waiting to false
                        _IsWaiting = false; //not waiting right now,will be waiting if necessary in the current move pattern
                        //reset _ElaspedMS1 as well
                        _ElapsedMs1 = Util.Cache.GameTime.TotalGameTime.TotalMilliseconds;

                        //force move pattern change
                        _UpdateMovePattern();

                        //remove this backup from the collection
                        World.WorldManager.StoredFOVs.RemoveAt(i);

                    }



                }

                //stop distracting
                IsDistracting = false;
                
                //clear the storedFOVS if no elements
                if (World.WorldManager.StoredFOVs.Count == 0)
                {
                    World.WorldManager.StoredFOVs = null;
                }

            }
            catch (Exception ex)
            {
                Util.ErrorLogging.LogError(ex);
                return;
            }

        }

        /// <summary>
        /// check if distracting item landed in
        /// npc's distraction control rectangle
        /// if yes distract npc
        /// </summary>
        public void Distract()
        {
            //declare
            Util.Classes.FieldOfViewBackup fovBackup = null;
            List<Util.Classes.DirectionSector> directionSectors = null;
            Util.Classes.DirectionSector directionSector;

            try
            {
                //distract npc 
                //if item thrown smashed in the distraction control rect
                //of npc

                #region were the item has been smashed?

                if(!World.WorldManager.IsObstacleTouched(_DistractionControlRect,new int[]{(int)World.WorldManager.ThrowPosition.X,(int)World.WorldManager.ThrowPosition.Y,(int)World.WorldManager.ThrownItem.Width,(int)World.WorldManager.ThrownItem.Height}))

                {
                     //if npc should not be distracted because an item has not
                //landed near the npc
                //then return
               
                    return;
                }

               

                #endregion

                #region backup current fov
                //loop through all fovs
                for (int i = 0; i < MovePatterns[MovePatternCt].FieldsOfView.Count; i++)
                {
                    //if current field of view, then modify
                    if (MovePatterns[MovePatternCt].FieldsOfView[i].OrderNumber == _FieldOfViewCT)
                    {
                        //new instance of fov backup
                        fovBackup = new Util.Classes.FieldOfViewBackup();
                        fovBackup.NPCID = this.UniqueID;
                        #region backup fov
                        fovBackup.Fov = new Helpers.MasterFOV();
                        fovBackup.Fov.Circles = MovePatterns[MovePatternCt].FieldsOfView[i].Circles;
                        fovBackup.Fov.Direction = MovePatterns[MovePatternCt].FieldsOfView[i].Direction;
                        fovBackup.Fov.OrderNumber = MovePatterns[MovePatternCt].FieldsOfView[i].OrderNumber;
                        fovBackup.Fov.Time = MovePatterns[MovePatternCt].FieldsOfView[i].Time;


                        #endregion


                        //backup move pattern
                        #region backup move pattern
                        fovBackup.CurrentMovePattern = new Helpers.MovePattern();
                        fovBackup.CurrentMovePattern.EndX = MovePatterns[MovePatternCt].EndX;
                        fovBackup.CurrentMovePattern.EndY = MovePatterns[MovePatternCt].EndY;
                        fovBackup.CurrentMovePattern.FieldsOfView = MovePatterns[MovePatternCt].FieldsOfView;
                        fovBackup.CurrentMovePattern.MoveDirection = MovePatterns[MovePatternCt].MoveDirection;
                        fovBackup.CurrentMovePattern.NPCCT = MovePatterns[MovePatternCt].NPCCT;
                        fovBackup.CurrentMovePattern.NPCID = MovePatterns[MovePatternCt].NPCID;
                        fovBackup.CurrentMovePattern.StartX = MovePatterns[MovePatternCt].StartX;
                        fovBackup.CurrentMovePattern.StartY = MovePatterns[MovePatternCt].StartY;
                        fovBackup.CurrentMovePattern.WaitTime = MovePatterns[MovePatternCt].WaitTime;
                        fovBackup.CurrentMovePattern.IsMoving = MovePatterns[MovePatternCt].IsMoving;
                        fovBackup.IsMoving = MovePatterns[MovePatternCt].IsMoving;
                        fovBackup.YReached = _YReached;
                        fovBackup.XReached = _XReached;
                        
                        fovBackup.CurrentMovePatternCt = MovePatternCt;


                        #endregion

                        #region determine new, distracted fov direction

                        #region first create direction sectors for help

                        //create the collection
                        if (directionSectors == null)
                        {
                            directionSectors = new List<Util.Classes.DirectionSector>();
                        }

                        #region sector A1

                        directionSector = new Util.Classes.DirectionSector(new Rectangle(_DistractionControlRect[0], _DistractionControlRect[1], this.CurrentPosX - _DistractionControlRect[0], this.CurrentPosY - _DistractionControlRect[1]), Util.Helpers.PublicEnums.NPCMoveDirection.crossUpLeft,"CrossUpLeft", "A1");
                        //add
                        directionSectors.Add(directionSector);

                        #endregion
                        #region sector A2

                        directionSector = new Util.Classes.DirectionSector(new Rectangle(this.CurrentPosX, _DistractionControlRect[1], this.CurrentPosX + this.Width, this.CurrentPosY - _DistractionControlRect[1]), Util.Helpers.PublicEnums.NPCMoveDirection.up,"Up", "A2");
                        //add
                        directionSectors.Add(directionSector);


                        #endregion
                        #region sector A3
                        directionSector = new Util.Classes.DirectionSector(new Rectangle(this.CurrentPosX + this.Width,  _DistractionControlRect[1], _DistractionControlRect[2] - this.Width-(this.CurrentPosX - _DistractionControlRect[0]), this.CurrentPosY - _DistractionControlRect[1]), Util.Helpers.PublicEnums.NPCMoveDirection.CrossUpRight,"CrossUpRight", "A3");
                        //add
                        directionSectors.Add(directionSector);

                        #endregion
                        #region sector A4

                        directionSector = new Util.Classes.DirectionSector(new Rectangle(this._DistractionControlRect[0], this.CurrentPosY, this.CurrentPosX - _DistractionControlRect[0], this.Height), Util.Helpers.PublicEnums.NPCMoveDirection.left, "Left", "A4");
                        //add
                        directionSectors.Add(directionSector);


                        #endregion
                        #region sector A5

                        directionSector = new Util.Classes.DirectionSector(new Rectangle(this.CurrentPosX + this.Width, this.CurrentPosY, _DistractionControlRect[2] - this.Width - (this.CurrentPosX - _DistractionControlRect[0]), this.Height), Util.Helpers.PublicEnums.NPCMoveDirection.right, "Right", "A5");
                        //add
                        directionSectors.Add(directionSector);


                        #endregion
                        #region sector A6

                        directionSector = new Util.Classes.DirectionSector(new Rectangle(this._DistractionControlRect[0], this.CurrentPosY + this.Height, this.CurrentPosX - _DistractionControlRect[0], this.CurrentPosY - _DistractionControlRect[1]), Util.Helpers.PublicEnums.NPCMoveDirection.crossDownLeft,"CrossDownLeft", "A6");
                        //add
                        directionSectors.Add(directionSector);


                        #endregion
                        #region sector A7

                        directionSector = new Util.Classes.DirectionSector(new Rectangle(this.CurrentPosX, this.CurrentPosY + this.Height, this.Width, this.CurrentPosY - _DistractionControlRect[1]), Util.Helpers.PublicEnums.NPCMoveDirection.down,"Down", "A7");
                        //add
                        directionSectors.Add(directionSector);


                        #endregion
                        #region sector A8

                        directionSector = new Util.Classes.DirectionSector(new Rectangle(this.CurrentPosX + this.Width, this.CurrentPosY + this.Height, _DistractionControlRect[2] - this.Width - (this.CurrentPosX - _DistractionControlRect[0]), this.CurrentPosY - _DistractionControlRect[1]), Util.Helpers.PublicEnums.NPCMoveDirection.crossDownRight, "CrossDownRight", "A8");
                        //add
                        directionSectors.Add(directionSector);


                        #endregion
                        #endregion

                        #region determine direction

                        for (int di = 0; di < directionSectors.Count; di++)
                        {
                            if(directionSectors[di].Rect.Intersects(new Rectangle((int)World.WorldManager.ThrowPosition.X,(int)World.WorldManager.ThrowPosition.Y,(int)World.WorldManager.ThrownItem.Width,(int)World.WorldManager.ThrownItem.Height)))
                            {
                                #region set directions
                                //set fov direction
                                MovePatterns[MovePatternCt].FieldsOfView[i].Direction = directionSectors[di].Direction2;
                                //set move pattern direction
                                MovePatterns[MovePatternCt].MoveDirection = directionSectors[di].Direction;
                                #endregion

                                #region set new wait time for move pattern and fov
                                //distraction makes NPC look in some direction for x seconds

                                MovePatterns[MovePatternCt].WaitTime = DetermineWaitTimeBasedOnIQ();
                                MovePatterns[MovePatternCt].FieldsOfView[i].Time = DetermineWaitTimeBasedOnIQ();


                                //set elapsed milliseconds values to now
                                MovePatterns[MovePatternCt].IsMoving = false;
                                
                                _ElapsedMs1 = Util.Cache.GameTime.TotalGameTime.TotalMilliseconds;
                                _ElapsedMs2 = Util.Cache.GameTime.TotalGameTime.TotalMilliseconds;



                                #endregion


                                //set is distracting to true for changes to take place
                                this.IsDistracting = true;
                                //clear the npc's perception field
                                this.ClearDistractionControl();
                               

                                break;
                            }

                        }

                        #endregion

                        #endregion

                      
                    }
 
                }

                //save current fov
                if (fovBackup != null)
                {
                    //save current fov
                    fovBackup.CurrentFov = _FieldOfViewCT;
                    fovBackup.IsCurrentFovTimed = _IsFieldOfViewTimed;
                   
                    //backup done, so modify property
                    _IsFieldOfViewTimed = true;
                    _IsWaiting = true;

                    //add backup to the list of stored fovs in world manager
                    if (World.WorldManager.StoredFOVs == null)
                    {
                        World.WorldManager.StoredFOVs = new List<Util.Classes.FieldOfViewBackup>();
                    }
                    //add
                    World.WorldManager.StoredFOVs.Add(fovBackup);
                }


                //get rid of unused objects
                directionSector = null;
                directionSectors = null;
                fovBackup = null;
                #endregion


            }
            catch (Exception ex)
            {
                Util.ErrorLogging.LogError(ex);
                return;
            } 
        }

        /// <summary>
        /// determine fov wait time
        /// basing on IQ
        /// </summary>
        /// <returns></returns>
        public int DetermineWaitTimeBasedOnIQ()
        {
            try
            {
                return this.IQ * 1000;



            }
            catch (Exception ex)
            {
                Util.ErrorLogging.LogError(ex);
                return 1;
            }


        }

        #endregion

        #region PRIVATE

        /// <summary>
        /// Prepare field of view for drawing
        /// </summary>
        private void _PrepareFieldOfView()
        {
            try
            {
               

                #region fields of view

                if (!_IsFieldOfViewTimed)
                {
                    //for each master view in the current move pattern
                    for (int i = 0; i < MovePatterns[MovePatternCt].FieldsOfView.Count; i++)
                    {
                        if (MovePatterns[MovePatternCt].FieldsOfView[i].OrderNumber == _FieldOfViewCT)
                        {
                            //it is current field of view
                            //assign circles to field of view rectangles
                            _FieldOfViewRect1 = new int[]{0,0, MovePatterns[MovePatternCt].FieldsOfView[i].Circles[0].Width, MovePatterns[MovePatternCt].FieldsOfView[i].Circles[0].Height};
                            _FieldOfViewRect2 = new int[]{0, 0, MovePatterns[MovePatternCt].FieldsOfView[i].Circles[1].Width, MovePatterns[MovePatternCt].FieldsOfView[i].Circles[1].Height};
                            _FieldOfViewRect3 = new int[]{0, 0, MovePatterns[MovePatternCt].FieldsOfView[i].Circles[2].Width, MovePatterns[MovePatternCt].FieldsOfView[i].Circles[2].Height};

                            //if this field of view lasts only x amount of time, then save current elapsed gametime
                            if (MovePatterns[MovePatternCt].FieldsOfView[i].Time > 0)
                            {
                                //save elapsed time up to this point (gametime)
                                _ElapsedMs2 = Util.Cache.GameTime.TotalGameTime.TotalMilliseconds;
                                _IsFieldOfViewTimed = true;
                                _CurrentFieldOfVIewTime = MovePatterns[MovePatternCt].FieldsOfView[i].Time;
                            }
                            else
                            {
                                //increase _fieldOfViewCT (only if  not bigger than list's capacity)
                                if (_FieldOfViewCT + 1 < MovePatterns[MovePatternCt].FieldsOfView.Count)
                                {
                                    _FieldOfViewCT += 1;
                                }
                                else
                                {
                                    //if avatar is not moving, then reset field of view ct here, otherwise it's resetted in UpdateMovePattern()
                                    if (!MovePatterns[MovePatternCt].IsMoving)
                                    {
                                        _FieldOfViewCT = 0;
                                    }
                                }
                            }

                            //break the loop
                            break;
                        }
                    }
                }
                else
                {
                    //if certain amount of time elapsed, increase
                    //field of view counter
                    if (Util.Cache.GameTime.TotalGameTime.TotalMilliseconds - _ElapsedMs2 >= _CurrentFieldOfVIewTime)
                    {
                        //time passed - proceed only if not distracting now
                        if (!IsDistracting)
                        {
                            _IsFieldOfViewTimed = false;
                            _CurrentFieldOfVIewTime = 0;
                            _ElapsedMs2 = 0;
                            //increase _fieldOfViewCT (only if  not bigger than list's capacity)
                            if (_FieldOfViewCT + 1 < MovePatterns[MovePatternCt].FieldsOfView.Count)
                            {
                                _FieldOfViewCT += 1;
                            }
                            else
                            {
                                //if avatar is not moving, then reset field of view ct here, otherwise it's resetted in UpdateMovePattern()
                                if (!MovePatterns[MovePatternCt].IsMoving)
                                {
                                    _FieldOfViewCT = 0;
                                }
                            }
                        }

                    }
                }

                #endregion

                //prepare fovs
                _CreateFOVCircles();


            }
            catch (Exception ex)
            {
                Util.ErrorLogging.LogError(ex);
                return;
            }


        }


        /// <summary>
        /// determine if avatar is away from the heat
        /// so if avatar has been spotted, and then moved away from npc
        /// npc returns to regular move pattern and stops shooting or wahtever
        /// </summary>
        /// <returns></returns>
        private bool _IsAvatarAwayFromHeat()
        {


            try
            {


                //see if avatar is away from heat rect
                if(World.WorldManager.IsObstacleTouched(World.WorldManager.HeatRectangle,new int[]{(int)Util.Cache.Avatar.CurrentPosition.X+Cache.Avatar.Offset,(int)Cache.Avatar.CurrentPosition.Y,Width - (Cache.Avatar.Offset * 2), Height - (Cache.Avatar.Offset * 2)}))
                {
                    return false; //false=avatar is not away from heat

                }


             

                return true;

            }
            catch (Exception ex)
            {
                Util.ErrorLogging.LogError(ex);
                return true;
            }
        }


        /// <summary>
        /// see if avatar is in the view (spotted!)
        /// </summary>
        private bool _IsAvatarHiddenBehindObstacle()
        {
            //declare
            //create rectangle for obstacle
           int[] obstacleRect;
            //Util.Helpers.PublicEnums.ShieldType obstacleShieldType;
            

            try
            {
                //if avatar is diving, and is spotted by npc, then return true-yes avatar is hidden
                if (Util.Cache.Avatar.Position == Util.Helpers.PublicEnums.AvatarPosition.Dive)
                {
                    return true;
                }


                 //foreach obstacle
                for (int i = 0; i < Levels.LevelManager.CurrentMap.CurrentMapCell.Obstacles.Count;i++)
                {
                    #region see if this obstacle is shielding


                    if (!Levels.LevelManager.CurrentMap.CurrentMapCell.Obstacles[i].ObstacleShieldTypeSet)
                    {
                        Levels.LevelManager.CurrentMap.CurrentMapCell.Obstacles[i].Shield = Levels.LevelManager.GetObstacleIsShieldType(Levels.LevelManager.CurrentMap.CurrentMapCell.Obstacles[i].ObstacleID);
                        Levels.LevelManager.CurrentMap.CurrentMapCell.Obstacles[i].ObstacleShieldTypeSet = true;
                    }

                    //if obstacle shield type is none, then this obstacle does not qualify to cover avatar. skip. For example, landmine does not cover
                    if (Levels.LevelManager.CurrentMap.CurrentMapCell.Obstacles[i].Shield == Util.Helpers.PublicEnums.ShieldType.None)
                    {
                        continue;

                    }
                   
                    #endregion

                    //create obstacle's rectangle
                    obstacleRect = new int[]{(int)Levels.LevelManager.CurrentMap.CurrentMapCell.Obstacles[i].Position.X, (int)Levels.LevelManager.CurrentMap.CurrentMapCell.Obstacles[i].Position.Y, Levels.LevelManager.CurrentMap.CurrentMapCell.Obstacles[i].Dimensions[0], Levels.LevelManager.CurrentMap.CurrentMapCell.Obstacles[i].Dimensions[1]};

                    //from NPC<obstacle|avatar(avatar cannot be seen in that spot)
                    switch (MovePatterns[MovePatternCt].MoveDirection)
                    {
                        case Util.Helpers.PublicEnums.NPCMoveDirection.right:
                            {

                                //check if there is an obstacle in front of avatar
                                //which covers him
                                //obstacle should be on the left side of avatar
                                if (MovePatterns[MovePatternCt].FieldsOfView[_FieldOfViewCT].FOVDirection == Util.Helpers.PublicEnums.FieldOfViewDirection.Right)
                                {
                                    if ((Levels.LevelManager.CurrentMap.CurrentMapCell.Obstacles[i].Position.X < Util.Cache.Avatar.CurrentPosition.X && Levels.LevelManager.CurrentMap.CurrentMapCell.Obstacles[i].Position.X > this.CurrentPosX) && ((Levels.LevelManager.CurrentMap.CurrentMapCell.Obstacles[i].Position.Y <= Util.Cache.Avatar.CurrentPosition.Y) && (Levels.LevelManager.CurrentMap.CurrentMapCell.Obstacles[i].Position.Y + obstacleRect[3] >= Util.Cache.Avatar.CurrentPosition.Y + Util.Cache.Avatar.Height)) && _ObstacleAndFOVRectsIntersect(obstacleRect))
                                    {
                                        //avatar is hidden by an obstacle
                                        return true;
                                    }
                                }


                                if (MovePatterns[MovePatternCt].FieldsOfView[_FieldOfViewCT].FOVDirection == Util.Helpers.PublicEnums.FieldOfViewDirection.CrossUpRight)
                                {
                                    if ((Levels.LevelManager.CurrentMap.CurrentMapCell.Obstacles[i].Position.Y > Util.Cache.Avatar.CurrentPosition.Y && Levels.LevelManager.CurrentMap.CurrentMapCell.Obstacles[i].Position.Y < this.CurrentPosY) && ((Levels.LevelManager.CurrentMap.CurrentMapCell.Obstacles[i].Position.X <= Util.Cache.Avatar.CurrentPosition.X) && (Levels.LevelManager.CurrentMap.CurrentMapCell.Obstacles[i].Position.X + obstacleRect[2] >= Util.Cache.Avatar.CurrentPosition.X + Util.Cache.Avatar.Width)) && _ObstacleAndFOVRectsIntersect(obstacleRect))
                                    {
                                        //avatar is hidden by an obstacle
                                        return true;
                                    }
                                }

                                if (MovePatterns[MovePatternCt].FieldsOfView[_FieldOfViewCT].FOVDirection == Util.Helpers.PublicEnums.FieldOfViewDirection.CrossDownRight)
                                {
                                    if ((Levels.LevelManager.CurrentMap.CurrentMapCell.Obstacles[i].Position.Y < Util.Cache.Avatar.CurrentPosition.Y && Levels.LevelManager.CurrentMap.CurrentMapCell.Obstacles[i].Position.Y > this.CurrentPosY) && ((Levels.LevelManager.CurrentMap.CurrentMapCell.Obstacles[i].Position.X <= Util.Cache.Avatar.CurrentPosition.X) && (Levels.LevelManager.CurrentMap.CurrentMapCell.Obstacles[i].Position.X + obstacleRect[2] >= Util.Cache.Avatar.CurrentPosition.X + Util.Cache.Avatar.Width)) && _ObstacleAndFOVRectsIntersect(obstacleRect))
                                    {
                                        //avatar is hidden by an obstacle
                                        return true;
                                    }
                                }

                                if (MovePatterns[MovePatternCt].FieldsOfView[_FieldOfViewCT].FOVDirection == Util.Helpers.PublicEnums.FieldOfViewDirection.Down)
                                {
                                    if ((Levels.LevelManager.CurrentMap.CurrentMapCell.Obstacles[i].Position.Y < Util.Cache.Avatar.CurrentPosition.Y && Levels.LevelManager.CurrentMap.CurrentMapCell.Obstacles[i].Position.Y > this.CurrentPosY) && ((Levels.LevelManager.CurrentMap.CurrentMapCell.Obstacles[i].Position.X <= Util.Cache.Avatar.CurrentPosition.X) && (Levels.LevelManager.CurrentMap.CurrentMapCell.Obstacles[i].Position.X + obstacleRect[2] >= Util.Cache.Avatar.CurrentPosition.X + Util.Cache.Avatar.Width)) && _ObstacleAndFOVRectsIntersect(obstacleRect))
                                    {
                                        //avatar is hidden by an obstacle
                                        return true;
                                    }
                                }

                                if (MovePatterns[MovePatternCt].FieldsOfView[_FieldOfViewCT].FOVDirection == Util.Helpers.PublicEnums.FieldOfViewDirection.Up)
                                {
                                    if ((Levels.LevelManager.CurrentMap.CurrentMapCell.Obstacles[i].Position.Y > Util.Cache.Avatar.CurrentPosition.Y && Levels.LevelManager.CurrentMap.CurrentMapCell.Obstacles[i].Position.Y < this.CurrentPosY) && ((Levels.LevelManager.CurrentMap.CurrentMapCell.Obstacles[i].Position.X <= Util.Cache.Avatar.CurrentPosition.X) && (Levels.LevelManager.CurrentMap.CurrentMapCell.Obstacles[i].Position.X + obstacleRect[2] >= Util.Cache.Avatar.CurrentPosition.X + Util.Cache.Avatar.Width)) && _ObstacleAndFOVRectsIntersect(obstacleRect))
                                    {
                                        //avatar is hidden by an obstacle
                                        return true;
                                    }
                                }



                                break;
                            }
                        case Util.Helpers.PublicEnums.NPCMoveDirection.left:
                            {
                                //check if there is an obstacle in front of avatar
                                //which covers him
                                //obstacle should be on the right side of avatar
                                if (MovePatterns[MovePatternCt].FieldsOfView[_FieldOfViewCT].FOVDirection==Util.Helpers.PublicEnums.FieldOfViewDirection.Left)
                                {

                                    if ((Levels.LevelManager.CurrentMap.CurrentMapCell.Obstacles[i].Position.X > Util.Cache.Avatar.CurrentPosition.X && Levels.LevelManager.CurrentMap.CurrentMapCell.Obstacles[i].Position.X < this.CurrentPosX) && ((Levels.LevelManager.CurrentMap.CurrentMapCell.Obstacles[i].Position.Y <= Util.Cache.Avatar.CurrentPosition.Y) && (Levels.LevelManager.CurrentMap.CurrentMapCell.Obstacles[i].Position.Y + obstacleRect[3] >= Util.Cache.Avatar.CurrentPosition.Y + Util.Cache.Avatar.Height)) && _ObstacleAndFOVRectsIntersect(obstacleRect))
                                    {
                                        //avatar is hidden by an obstacle
                                        return true;
                                    }
                                }

                                
                                if (MovePatterns[MovePatternCt].FieldsOfView[_FieldOfViewCT].FOVDirection == Util.Helpers.PublicEnums.FieldOfViewDirection.CrossDownLeft)
                                {
                                    if ((Levels.LevelManager.CurrentMap.CurrentMapCell.Obstacles[i].Position.Y < Util.Cache.Avatar.CurrentPosition.Y && Levels.LevelManager.CurrentMap.CurrentMapCell.Obstacles[i].Position.Y > this.CurrentPosY) && ((Levels.LevelManager.CurrentMap.CurrentMapCell.Obstacles[i].Position.X <= Util.Cache.Avatar.CurrentPosition.X) && (Levels.LevelManager.CurrentMap.CurrentMapCell.Obstacles[i].Position.X + obstacleRect[2] >= Util.Cache.Avatar.CurrentPosition.X + Util.Cache.Avatar.Width)) && _ObstacleAndFOVRectsIntersect(obstacleRect))
                                    {
                                        //avatar is hidden by an obstacle
                                        return true;
                                    }
                                }

                                if (MovePatterns[MovePatternCt].FieldsOfView[_FieldOfViewCT].FOVDirection == Util.Helpers.PublicEnums.FieldOfViewDirection.CrossUpLeft)
                                {
                                    if ((Levels.LevelManager.CurrentMap.CurrentMapCell.Obstacles[i].Position.Y > Util.Cache.Avatar.CurrentPosition.Y && Levels.LevelManager.CurrentMap.CurrentMapCell.Obstacles[i].Position.Y < this.CurrentPosY) && ((Levels.LevelManager.CurrentMap.CurrentMapCell.Obstacles[i].Position.X <= Util.Cache.Avatar.CurrentPosition.X) && (Levels.LevelManager.CurrentMap.CurrentMapCell.Obstacles[i].Position.X + obstacleRect[2] >= Util.Cache.Avatar.CurrentPosition.X + Util.Cache.Avatar.Width)) && _ObstacleAndFOVRectsIntersect(obstacleRect))
                                    {
                                        //avatar is hidden by an obstacle
                                        return true;
                                    }
                                }


                                if (MovePatterns[MovePatternCt].FieldsOfView[_FieldOfViewCT].FOVDirection == Util.Helpers.PublicEnums.FieldOfViewDirection.Down)
                                {
                                    if ((Levels.LevelManager.CurrentMap.CurrentMapCell.Obstacles[i].Position.Y < Util.Cache.Avatar.CurrentPosition.Y && Levels.LevelManager.CurrentMap.CurrentMapCell.Obstacles[i].Position.Y > this.CurrentPosY) && ((Levels.LevelManager.CurrentMap.CurrentMapCell.Obstacles[i].Position.X <= Util.Cache.Avatar.CurrentPosition.X) && (Levels.LevelManager.CurrentMap.CurrentMapCell.Obstacles[i].Position.X + obstacleRect[2] >= Util.Cache.Avatar.CurrentPosition.X + Util.Cache.Avatar.Width)) && _ObstacleAndFOVRectsIntersect(obstacleRect))
                                    {
                                        //avatar is hidden by an obstacle
                                        return true;
                                    }
                                }


                                if (MovePatterns[MovePatternCt].FieldsOfView[_FieldOfViewCT].FOVDirection == Util.Helpers.PublicEnums.FieldOfViewDirection.Up)
                                {
                                    if ((Levels.LevelManager.CurrentMap.CurrentMapCell.Obstacles[i].Position.Y > Util.Cache.Avatar.CurrentPosition.Y && Levels.LevelManager.CurrentMap.CurrentMapCell.Obstacles[i].Position.Y < this.CurrentPosY) && ((Levels.LevelManager.CurrentMap.CurrentMapCell.Obstacles[i].Position.X <= Util.Cache.Avatar.CurrentPosition.X) && (Levels.LevelManager.CurrentMap.CurrentMapCell.Obstacles[i].Position.X + obstacleRect[2] >= Util.Cache.Avatar.CurrentPosition.X + Util.Cache.Avatar.Width)) && _ObstacleAndFOVRectsIntersect(obstacleRect))
                                    {
                                        //avatar is hidden by an obstacle
                                        return true;
                                    }
                                }


                                break;
                            }
                        case Util.Helpers.PublicEnums.NPCMoveDirection.down:
                            {

                                if (MovePatterns[MovePatternCt].FieldsOfView[_FieldOfViewCT].FOVDirection == Util.Helpers.PublicEnums.FieldOfViewDirection.Down)
                                {
                                    if ((Levels.LevelManager.CurrentMap.CurrentMapCell.Obstacles[i].Position.Y < Util.Cache.Avatar.CurrentPosition.Y && Levels.LevelManager.CurrentMap.CurrentMapCell.Obstacles[i].Position.Y > this.CurrentPosY) && ((Levels.LevelManager.CurrentMap.CurrentMapCell.Obstacles[i].Position.X <= Util.Cache.Avatar.CurrentPosition.X) && (Levels.LevelManager.CurrentMap.CurrentMapCell.Obstacles[i].Position.X + obstacleRect[2] >= Util.Cache.Avatar.CurrentPosition.X + Util.Cache.Avatar.Width)) && _ObstacleAndFOVRectsIntersect(obstacleRect))
                                    {
                                        //avatar is hidden by an obstacle
                                        return true;
                                    }
                                }

                                if (MovePatterns[MovePatternCt].FieldsOfView[_FieldOfViewCT].FOVDirection == Util.Helpers.PublicEnums.FieldOfViewDirection.CrossDownLeft)
                                {
                                    if ((Levels.LevelManager.CurrentMap.CurrentMapCell.Obstacles[i].Position.X > Util.Cache.Avatar.CurrentPosition.X && Levels.LevelManager.CurrentMap.CurrentMapCell.Obstacles[i].Position.X < this.CurrentPosX) && ((Levels.LevelManager.CurrentMap.CurrentMapCell.Obstacles[i].Position.Y <= Util.Cache.Avatar.CurrentPosition.Y) && (Levels.LevelManager.CurrentMap.CurrentMapCell.Obstacles[i].Position.Y + obstacleRect[3] >= Util.Cache.Avatar.CurrentPosition.Y + Util.Cache.Avatar.Height)) && _ObstacleAndFOVRectsIntersect(obstacleRect))
                                    {
                                        //avatar is hidden by an obstacle
                                        return true;
                                    }
                                }

                                if (MovePatterns[MovePatternCt].FieldsOfView[_FieldOfViewCT].FOVDirection == Util.Helpers.PublicEnums.FieldOfViewDirection.CrossDownRight)
                                {
                                    if ((Levels.LevelManager.CurrentMap.CurrentMapCell.Obstacles[i].Position.X < Util.Cache.Avatar.CurrentPosition.X && Levels.LevelManager.CurrentMap.CurrentMapCell.Obstacles[i].Position.X > this.CurrentPosX) && ((Levels.LevelManager.CurrentMap.CurrentMapCell.Obstacles[i].Position.Y <= Util.Cache.Avatar.CurrentPosition.Y) && (Levels.LevelManager.CurrentMap.CurrentMapCell.Obstacles[i].Position.Y + obstacleRect[3] >= Util.Cache.Avatar.CurrentPosition.Y + Util.Cache.Avatar.Height)) && _ObstacleAndFOVRectsIntersect(obstacleRect))
                                    {
                                        //avatar is hidden by an obstacle
                                        return true;
                                    }
                                }


                                break;
                            }
                        case Util.Helpers.PublicEnums.NPCMoveDirection.up:
                            {
                                if (MovePatterns[MovePatternCt].FieldsOfView[_FieldOfViewCT].FOVDirection == Util.Helpers.PublicEnums.FieldOfViewDirection.Up)
                                {
                                    if ((Levels.LevelManager.CurrentMap.CurrentMapCell.Obstacles[i].Position.Y > Util.Cache.Avatar.CurrentPosition.Y && Levels.LevelManager.CurrentMap.CurrentMapCell.Obstacles[i].Position.Y < this.CurrentPosY) && ((Levels.LevelManager.CurrentMap.CurrentMapCell.Obstacles[i].Position.X <= Util.Cache.Avatar.CurrentPosition.X) && (Levels.LevelManager.CurrentMap.CurrentMapCell.Obstacles[i].Position.X + obstacleRect[2] >= Util.Cache.Avatar.CurrentPosition.X + Util.Cache.Avatar.Width)) && _ObstacleAndFOVRectsIntersect(obstacleRect))
                                    {
                                        //avatar is hidden by an obstacle
                                        return true;
                                    }
                                }

                                if (MovePatterns[MovePatternCt].FieldsOfView[_FieldOfViewCT].FOVDirection == Util.Helpers.PublicEnums.FieldOfViewDirection.CrossUpLeft)
                                {
                                    if ((Levels.LevelManager.CurrentMap.CurrentMapCell.Obstacles[i].Position.X > Util.Cache.Avatar.CurrentPosition.X && Levels.LevelManager.CurrentMap.CurrentMapCell.Obstacles[i].Position.X < this.CurrentPosX) && ((Levels.LevelManager.CurrentMap.CurrentMapCell.Obstacles[i].Position.Y <= Util.Cache.Avatar.CurrentPosition.Y) && (Levels.LevelManager.CurrentMap.CurrentMapCell.Obstacles[i].Position.Y + obstacleRect[3] >= Util.Cache.Avatar.CurrentPosition.Y + Util.Cache.Avatar.Height)) && _ObstacleAndFOVRectsIntersect(obstacleRect))
                                    {
                                        //avatar is hidden by an obstacle
                                        return true;
                                    }
                                }

                                if (MovePatterns[MovePatternCt].FieldsOfView[_FieldOfViewCT].FOVDirection == Util.Helpers.PublicEnums.FieldOfViewDirection.CrossUpRight)
                                {
                                    if ((Levels.LevelManager.CurrentMap.CurrentMapCell.Obstacles[i].Position.X < Util.Cache.Avatar.CurrentPosition.X && Levels.LevelManager.CurrentMap.CurrentMapCell.Obstacles[i].Position.X > this.CurrentPosX) && ((Levels.LevelManager.CurrentMap.CurrentMapCell.Obstacles[i].Position.Y <= Util.Cache.Avatar.CurrentPosition.Y) && (Levels.LevelManager.CurrentMap.CurrentMapCell.Obstacles[i].Position.Y + obstacleRect[3] >= Util.Cache.Avatar.CurrentPosition.Y + Util.Cache.Avatar.Height)) && _ObstacleAndFOVRectsIntersect(obstacleRect))
                                    {
                                        //avatar is hidden by an obstacle
                                        return true;
                                    }
                                }

                                break;
                            }
                       
                    }

                }


                return false;
                
            }
            catch (Exception ex)
            {
                Util.ErrorLogging.LogError(ex);
                return false;
            }
        }


        /// <summary>
        /// check if obstacle rectangle
        /// and one of fov rectangles interesect
        /// </summary>
        /// <param name="obstacleRect"></param>
        /// <returns></returns>
        private bool _ObstacleAndFOVRectsIntersect(int[] obstacleRect)
        {
            try
            {
                if (_FieldOfViewRect1 != null && _FieldOfViewRect2 != null && _FieldOfViewRect3 != null)
                {
                    if (World.WorldManager.IsObstacleTouched(_FieldOfViewRect1,obstacleRect))
                    {
                        return true;
                    }

                    if (World.WorldManager.IsObstacleTouched(_FieldOfViewRect2, obstacleRect))
                    {
                        return true;
                    }

                    if (World.WorldManager.IsObstacleTouched(_FieldOfViewRect3, obstacleRect))
                    {
                        return true;
                    }

                }

                return false;
            }
            catch (Exception ex)
            {
                Util.ErrorLogging.LogError(ex);
                return false;
            }
        }


        /// <summary>
        /// Get texture, by its type
        /// </summary>
        /// <param name="type"></param>
        /// <returns></returns>
        private string _GetTextureNameByType(Util.Helpers.PublicEnums.NPCTextureType type)
        {
            try
            {
                for (int i = 0; i < this.Textures.Count; i++)
                {
                    if (this.Textures[i].TextureType == type)
                    {
                      
                        return this.Textures[i].ID;
                    }
                }

                return string.Empty;

            }
            catch (Exception ex)
            {
                Util.ErrorLogging.LogError(ex);
                return string.Empty;
            }
        }

        /// <summary>
        /// get texture instance by type
        /// </summary>
        /// <param name="type"></param>
        /// <returns></returns>
        private Texture2D _GetTextureInstanceByType(Util.Helpers.PublicEnums.NPCTextureType type)
        {
            try
            {
                for (int i = 0; i < this.Textures.Count; i++)
                {
                    if (this.Textures[i].TextureType == type)
                    {

                        return Util.Cache.GetTexture(this.Textures[i].ID).Text2D;
                    }
                }

                return null;

            }
            catch (Exception ex)
            {
                Util.ErrorLogging.LogError(ex);
                return null;
            }
        }


        /// <summary>
        /// see if avatar is in the view (spotted!)
        /// </summary>
        private void _DetectAvatar()
        {
            //declare
            //create rectangle for avatar
            int[] avatarRect;
           

            try
            {
                if (_AvatarSpotted || MovePatterns[MovePatternCt].FieldsOfView.Count == 0 || _IsHeatCooling || World.WorldManager.PauseON)
                {
                    //if avatar is already spotted, then return
                    //or if there are no fov in this move pattern
                    return;
                }



                
                if (_FieldOfViewRect1 != null && _FieldOfViewRect2 != null && _FieldOfViewRect3 != null)
                {
                    avatarRect = new int[]{(int)Cache.Avatar.CurrentPosition.X + Cache.Avatar.Offset, (int)Cache.Avatar.CurrentPosition.Y, Width - (Cache.Avatar.Offset * 2), Height - (Cache.Avatar.Offset * 2)};

                    //reset _whichFOVRectSpottedAvatar
                    _WhichFOVRectSpottedAvatar = -1; //for now, none

                    #region see which rectangle spotted avatar
                    //rect 1 spotted avatar?
                    if (World.WorldManager.IsObstacleTouched(_FieldOfViewRect1,avatarRect))
                    {
                        _WhichFOVRectSpottedAvatar = 0;
                    }
                    //rect 2 spotted avatar?
                    else if (World.WorldManager.IsObstacleTouched(_FieldOfViewRect2,avatarRect))
                    {
                        _WhichFOVRectSpottedAvatar = 1;
                    }
                    //rect 3 spotted avatar?
                    else if (World.WorldManager.IsObstacleTouched(_FieldOfViewRect3, avatarRect))
                    {
                        _WhichFOVRectSpottedAvatar = 2;
                    }

                    //if avatar touches npc's body
                    if (World.WorldManager.IsObstacleTouched(new int[] { this.CurrentPosX, this.CurrentPosY, this.Width, this.Height }, new int[] { (int)Util.Cache.Avatar.CurrentPosition.X, (int)Util.Cache.Avatar.CurrentPosition.Y, Util.Cache.Avatar.Width, Util.Cache.Avatar.Height }))
                    {
                        _WhichFOVRectSpottedAvatar = 1;
                    }


                    #endregion


                    //if _wchichFOVRectSpottedAVatar greater than -1, it means that avatar has been spotted by one of 1 FOV circles
                    if (_WhichFOVRectSpottedAvatar > -1)
                    {
                       
                        //save npc that spotted id
                        Util.Cache.Avatar.NpcThatSpottedID = this.ID;

                        this._InTheMiddleOfShooting = false;

                        //avatar spotted , but might be hidden by an obstacle
                        if (!_IsAvatarHiddenBehindObstacle())
                        {
                            _AvatarSpotted = true;
                            Util.Cache.Avatar.IsSpottedByNPCButHidden = false; //not hidden
                            this._stepBeforeStop = this.Step;
                            //set step to 0 (avatar spotted, NPC is not moving anymore)
                            this.Step = 0;

                            //if choosing mode or scanning in progress-cancel
                            if (World.ScannerManager.ChoosingNodes || World.ScannerManager.IsScanning)
                            {

                                World.ScannerManager.EndScanning = true;
                                World.ScannerManager.ExitChooseNodesMode();

                            }

                            //cancel avatar's move pattern
                            //to make it more difficult for user (if following)
                            //if (Util.Cache.Avatar.IsFollowing)
                            //{
                            //    Util.Cache.Avatar.EndFollowing();
                            //}

                            //raise avatar spotted event (different event, based on which fov circle spotted it)
                            #region what event to raise

                            switch (_WhichFOVRectSpottedAvatar)
                            {
                                case 0:
                                    {
                                        World.EventHandler.RaiseEvent(World.EventHandler.GetEventByType(Util.Helpers.PublicEnums.EventType.onAvatarSpotted, this.Events));
                                        break;
                                    }
                                case 1:
                                    {
                                        World.EventHandler.RaiseEvent(World.EventHandler.GetEventByType(Util.Helpers.PublicEnums.EventType.onAvatarSpotted, this.Events));
                                        break;
                                    }
                                case 2:
                                    {
                                        World.EventHandler.RaiseEvent(World.EventHandler.GetEventByType(Util.Helpers.PublicEnums.EventType.onAvatarSpotted, this.Events));
                                        break;
                                    }

                            }

                            #endregion

                            //save current elapsed milisencds
                            _ElapsedMs1 = Util.Cache.GameTime.TotalGameTime.TotalMilliseconds;
                        }
                        else
                        {
                            //avatar is hidden
                            //if not in the middle of awarding points, award points AND if not awarded points in this move pattern already
                            #region achievement-avatar spotted but hidden -obscure
                            //if (!World.WorldManager.AddingPoints && !MovePatterns[MovePatternCt].WellHiddenAcheivementDoneAlready)
                            //{
                            //    World.WorldManager.AwardPoints(Util.Helpers.PublicEnums.AcheivementType.AvatarHidden, 1000);
                            //    MovePatterns[MovePatternCt].WellHiddenAcheivementDoneAlready = true; //set this flag so the achievement is not awarded again in this move pattern
                            //}
                            #endregion
                            Util.Cache.Avatar.SetAvatarSpottedButHidden(_FieldOfViewRect1, _FieldOfViewRect2, _FieldOfViewRect3);


                        }

                    }
                    else
                    {
                        //set not spotted only if the same npc that spotted avatar does not see him anymore
                        if (Util.Cache.Avatar.NpcThatSpottedID == this.ID)
                        {
                            _AvatarSpotted = false;
                            //avatar is not spotted at al
                            Util.Cache.Avatar.IsSpottedByNPCButHidden = false; //not hidden
                            this._InTheMiddleOfShooting = false;
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                Util.ErrorLogging.LogError(ex);
                return;
            }
        }


        /// <summary>
        /// draw rectangle showing where player will be hit
        /// and where player can run away from heat to be safe
        /// </summary>
        private void _DrawHeat()
        {
           
            

            try
            {
                //if heat already drawn, then do not attempt to prepare heat again, just draw


                if (!HeatDrawn)
                {
                     

                     #region prepare heat rect

                    if (MovePatterns[MovePatternCt].FieldsOfView[_FieldOfViewCT].FOVDirection == Util.Helpers.PublicEnums.FieldOfViewDirection.None)
                    {
                        MovePatterns[MovePatternCt].FieldsOfView[_FieldOfViewCT].DetermineFOVDirection();
                           
                    }

                     switch (MovePatterns[MovePatternCt].FieldsOfView[_FieldOfViewCT].FOVDirection)
                     {
                         case Util.Helpers.PublicEnums.FieldOfViewDirection.Right:
                             {
                                 World.WorldManager.HeatRectangle = new int[] { this.CurrentPosX - 30, this.CurrentPosY - this.Height, (this.Width * 2) + _FieldOfViewRect1[2] + _FieldOfViewRect2[2] + _FieldOfViewRect3[2] + (Util.Cache.Avatar.Width * 2), (this.Height * 3) + Util.Cache.Avatar.Height };


                                 break;
                             }
                         case Util.Helpers.PublicEnums.FieldOfViewDirection.Left:
                             {
                                 World.WorldManager.HeatRectangle = new int[] { (int)Util.Cache.Avatar.CurrentPosition.X - 30, (int)Util.Cache.Avatar.CurrentPosition.Y - Util.Cache.Avatar.Height, (this.Width * 2) + _FieldOfViewRect1[2] + _FieldOfViewRect2[2] + _FieldOfViewRect3[2] + (Util.Cache.Avatar.Width * 2), (this.Height * 3) + Util.Cache.Avatar.Height };


                                 break;
                             }
                         case Util.Helpers.PublicEnums.FieldOfViewDirection.CrossDownRight:
                             {


                                 World.WorldManager.HeatRectangle = new int[] { this.CurrentPosX - 30, this.CurrentPosY - this.Height, (this.Width * 2) + _FieldOfViewRect1[2] + _FieldOfViewRect2[2] + _FieldOfViewRect3[2], (_FieldOfViewRect1[3] + _FieldOfViewRect2[3] + _FieldOfViewRect3[3]) + this.Height };
                                 break;
                             }
                         case Util.Helpers.PublicEnums.FieldOfViewDirection.CrossDownLeft:
                             {


                                 World.WorldManager.HeatRectangle = new int[] { (int)Util.Cache.Avatar.CurrentPosition.X - 30, (int)Util.Cache.Avatar.CurrentPosition.Y - this.Height, (this.Width * 2) + _FieldOfViewRect1[2] + _FieldOfViewRect2[2] + _FieldOfViewRect3[2] + (Util.Cache.Avatar.Width * 2), (this.Height * 3) + Cache.Avatar.Height };

                                 break;
                             }
                         case Util.Helpers.PublicEnums.FieldOfViewDirection.CrossUpRight:
                             {
                                 World.WorldManager.HeatRectangle = new int[] { this.CurrentPosX - (_FieldOfViewRect1[3] + _FieldOfViewRect2[3] + _FieldOfViewRect3[3] + this.Height), this.CurrentPosY - this.Height, (this.Width * 2) + _FieldOfViewRect1[2] + _FieldOfViewRect2[2] + _FieldOfViewRect3[2], (_FieldOfViewRect1[3] + _FieldOfViewRect2[3] + _FieldOfViewRect3[3]) + this.Height };

                                 break;
                             }
                         case Util.Helpers.PublicEnums.FieldOfViewDirection.CrossUpLeft:
                             {
                                 World.WorldManager.HeatRectangle = new int[] { (int)Util.Cache.Avatar.CurrentPosition.X - (_FieldOfViewRect1[3] + _FieldOfViewRect2[3] + _FieldOfViewRect3[3] + this.Height), (int)Util.Cache.Avatar.CurrentPosition.Y - this.Height, (this.Width * 2) + _FieldOfViewRect1[2] + _FieldOfViewRect2[2] + _FieldOfViewRect3[2] + (Util.Cache.Avatar.Width * 2), (_FieldOfViewRect1[3] + _FieldOfViewRect2[3] + _FieldOfViewRect3[3]) + Cache.Avatar.Height };

                                 break;
                             }
                         case Util.Helpers.PublicEnums.FieldOfViewDirection.Up:
                             {
                                 World.WorldManager.HeatRectangle = new int[] { (int)Cache.Avatar.CurrentPosition.X - this.Width / 2, (int)Cache.Avatar.CurrentPosition.Y - this.Height / 2, (this.Width * 3), (this.Height * 2) + _FieldOfViewRect1[3] + _FieldOfViewRect2[3] + _FieldOfViewRect3[3] + Cache.Avatar.Height };

                                 break;
                             }
                         case Util.Helpers.PublicEnums.FieldOfViewDirection.Down:
                             {
                                 World.WorldManager.HeatRectangle = new int[] { this.CurrentPosX - this.Width / 2, this.CurrentPosY - this.Height / 2, (this.Width * 3), (this.Height * 2) + _FieldOfViewRect1[3] + _FieldOfViewRect2[3] + _FieldOfViewRect3[3] };

                                 break;
                             }

                     }


                }

                     #endregion

                     #region draw

                if (World.WorldManager.HeatRectangle == null)
                {
                    return;
                }

                //first, draw field where the heat is
                Util.Cache.Draw(Util.Cache.GetTexture("heat1").Text2D,  World.WorldManager.HeatRectangle, Color.White);
                //draw greyed out free of heat area
                //grey out left from the heat rect
                //see if there is a space 
                #region left
                if (World.WorldManager.HeatRectangle[0] > 0)
                {
                    //there is a space on the left
                    Util.Cache.Draw(Util.Cache.GetTexture("heat").Text2D, new int[]{0, 0,  World.WorldManager.HeatRectangle[0], Util.Cache.GraphicsDevice.Viewport.Height}, Color.White);
                }
                #endregion

                #region up

                if (World.WorldManager.HeatRectangle[1]> 0)
                {
                    //there is a space on top of the heat rect
                    Util.Cache.Draw(Util.Cache.GetTexture("heat").Text2D, new int[]{World.WorldManager.HeatRectangle[0], 0,  World.WorldManager.HeatRectangle[2],  World.WorldManager.HeatRectangle[1]}, Color.White);
                }

                #endregion

                #region right

                if (Cache.GraphicsDevice.Viewport.Width -  (World.WorldManager.HeatRectangle[0]+World.WorldManager.HeatRectangle[2]) > 0)
                {
                    //there's space on the right
                    Util.Cache.Draw(Util.Cache.GetTexture("heat").Text2D, new int[] { World.WorldManager.HeatRectangle[0] + World.WorldManager.HeatRectangle[2], 0, Cache.GraphicsDevice.Viewport.Width - (World.WorldManager.HeatRectangle[0] + World.WorldManager.HeatRectangle[2]), Util.Cache.GraphicsDevice.Viewport.Height }, Color.White);

                }


                #endregion

                #region bottom

                if (Cache.GraphicsDevice.Viewport.Height -  (World.WorldManager.HeatRectangle[1]+World.WorldManager.HeatRectangle[3]) > 0)
                {
                    //there's space on the bttom
                    Util.Cache.Draw(Util.Cache.GetTexture("heat").Text2D, new int[]{World.WorldManager.HeatRectangle[0], World.WorldManager.HeatRectangle[1] + World.WorldManager.HeatRectangle[3], World.WorldManager.HeatRectangle[2], Cache.GraphicsDevice.Viewport.Height - (World.WorldManager.HeatRectangle[1]+World.WorldManager.HeatRectangle[3])}, Color.White);
                }



                #endregion


                #endregion

                //set heat drawn to true
                HeatDrawn = true;
                World.WorldManager.IsHeatActive = true;



            }
            catch (Exception ex)
            {
                Util.ErrorLogging.LogError(ex);
                return;
            }
        }

        /// <summary>
        /// create FOV circles
        /// </summary>
        private void _CreateFOVCircles()
        {
            try
            {
                //determine fov direction
                MovePatterns[MovePatternCt].FieldsOfView[_FieldOfViewCT].DetermineFOVDirection();

                #region determine direction

                switch (MovePatterns[MovePatternCt].FieldsOfView[_FieldOfViewCT].FOVDirection)
                {
                    case Util.Helpers.PublicEnums.FieldOfViewDirection.Right:
                        {
                            //first, update X,Y coordinates of 3 field of view rectangles
                            #region RIGHT

                            #region rectangle 1

                            _FieldOfViewRect1[0] = (this.CurrentPosX + this.Width) - MovePatterns[MovePatternCt].FieldsOfView[_FieldOfViewCT].Circles[0].OffsetX;
                            _FieldOfViewRect1[1] = this.CurrentPosY - MovePatterns[MovePatternCt].FieldsOfView[_FieldOfViewCT].Circles[0].OffsetY;

                            #endregion

                            #region rectangle 2
                            _FieldOfViewRect2[0]= (_FieldOfViewRect1[0] + _FieldOfViewRect1[2]) - MovePatterns[MovePatternCt].FieldsOfView[_FieldOfViewCT].Circles[1].OffsetX;
                            _FieldOfViewRect2[1]= _FieldOfViewRect1[1] + MovePatterns[MovePatternCt].FieldsOfView[_FieldOfViewCT].Circles[1].OffsetY;

                            #endregion

                            #region rectangle 3
                            _FieldOfViewRect3[0] = (_FieldOfViewRect2[0] + _FieldOfViewRect2[2]) - MovePatterns[MovePatternCt].FieldsOfView[_FieldOfViewCT].Circles[2].OffsetX;
                            _FieldOfViewRect3[1] = _FieldOfViewRect2[1] + MovePatterns[MovePatternCt].FieldsOfView[_FieldOfViewCT].Circles[2].OffsetY;

                            #endregion

                            #endregion

                            break;
                        }
                    case Util.Helpers.PublicEnums.FieldOfViewDirection.Left:
                        {
                            //first, update X,Y coordinates of 3 field of view rectangles
                            #region LEFT

                            #region rectangle 1

                            _FieldOfViewRect1[0] = (this.CurrentPosX - _FieldOfViewRect1[2]) + MovePatterns[MovePatternCt].FieldsOfView[_FieldOfViewCT].Circles[0].OffsetX;
                            _FieldOfViewRect1[1] = this.CurrentPosY - MovePatterns[MovePatternCt].FieldsOfView[_FieldOfViewCT].Circles[0].OffsetY;

                            #endregion

                            #region rectangle 2
                            _FieldOfViewRect2[0] = (_FieldOfViewRect1[0] - _FieldOfViewRect2[2]) + MovePatterns[MovePatternCt].FieldsOfView[_FieldOfViewCT].Circles[1].OffsetX;
                            _FieldOfViewRect2[1] = _FieldOfViewRect1[1] + MovePatterns[MovePatternCt].FieldsOfView[_FieldOfViewCT].Circles[1].OffsetY;

                            #endregion

                            #region rectangle 3
                            _FieldOfViewRect3[0] = (_FieldOfViewRect2[0] - _FieldOfViewRect3[2]) + MovePatterns[MovePatternCt].FieldsOfView[_FieldOfViewCT].Circles[2].OffsetX;
                            _FieldOfViewRect3[1] = _FieldOfViewRect2[1] + MovePatterns[MovePatternCt].FieldsOfView[_FieldOfViewCT].Circles[2].OffsetY;

                            #endregion

                            #endregion



                            break;
                        }
                    case Util.Helpers.PublicEnums.FieldOfViewDirection.CrossDownRight:
                        {

                            //first, update X,Y coordinates of 3 field of view rectangles
                            #region CROSS DOWN RIGHT

                            #region rectangle 1

                            _FieldOfViewRect1[0]= (this.CurrentPosX + this.Width) - MovePatterns[MovePatternCt].FieldsOfView[_FieldOfViewCT].Circles[0].OffsetX;
                            _FieldOfViewRect1[1] = (this.CurrentPosY + this.Height) - MovePatterns[MovePatternCt].FieldsOfView[_FieldOfViewCT].Circles[0].OffsetY;

                            #endregion

                            #region rectangle 2
                            _FieldOfViewRect2[0] = (_FieldOfViewRect1[0] + _FieldOfViewRect1[2]) - MovePatterns[MovePatternCt].FieldsOfView[_FieldOfViewCT].Circles[1].OffsetX;
                            _FieldOfViewRect2[1] = (_FieldOfViewRect1[1] + _FieldOfViewRect1[3]) - MovePatterns[MovePatternCt].FieldsOfView[_FieldOfViewCT].Circles[1].OffsetY;

                            #endregion

                            #region rectangle 3
                            _FieldOfViewRect3[0] = (_FieldOfViewRect2[0] + _FieldOfViewRect2[2]) - MovePatterns[MovePatternCt].FieldsOfView[_FieldOfViewCT].Circles[2].OffsetX;
                            _FieldOfViewRect3[1] = (_FieldOfViewRect2[1] + _FieldOfViewRect2[3]) - MovePatterns[MovePatternCt].FieldsOfView[_FieldOfViewCT].Circles[2].OffsetY;

                            #endregion

                            #endregion

                            break;
                        }
                    case Util.Helpers.PublicEnums.FieldOfViewDirection.CrossDownLeft:
                        {
                            //first, update X,Y coordinates of 3 field of view rectangles
                            #region CROSS DOWN LEFT

                            #region rectangle 1

                            _FieldOfViewRect1[0] = (this.CurrentPosX - _FieldOfViewRect1[2]) + MovePatterns[MovePatternCt].FieldsOfView[_FieldOfViewCT].Circles[0].OffsetX;
                            _FieldOfViewRect1[1] = (this.CurrentPosY + this.Height) - MovePatterns[MovePatternCt].FieldsOfView[_FieldOfViewCT].Circles[0].OffsetY;

                            #endregion

                            #region rectangle 2
                            _FieldOfViewRect2[0]= (_FieldOfViewRect1[0] - _FieldOfViewRect2[2]) + MovePatterns[MovePatternCt].FieldsOfView[_FieldOfViewCT].Circles[1].OffsetX;
                            _FieldOfViewRect2[1] = (_FieldOfViewRect1[1] + _FieldOfViewRect1[3]) - MovePatterns[MovePatternCt].FieldsOfView[_FieldOfViewCT].Circles[1].OffsetY;

                            #endregion

                            #region rectangle 3
                            _FieldOfViewRect3[0] = (_FieldOfViewRect2[0] - _FieldOfViewRect3[2]) + MovePatterns[MovePatternCt].FieldsOfView[_FieldOfViewCT].Circles[2].OffsetX;
                            _FieldOfViewRect3[1] = (_FieldOfViewRect2[1] + _FieldOfViewRect2[3]) - MovePatterns[MovePatternCt].FieldsOfView[_FieldOfViewCT].Circles[2].OffsetY;

                            #endregion

                            #endregion

                            break;
                        }
                    case Util.Helpers.PublicEnums.FieldOfViewDirection.CrossUpRight:
                        {
                            //first, update X,Y coordinates of 3 field of view rectangles
                            #region CROSS UP RIGHT

                            #region rectangle 1

                            _FieldOfViewRect1[0] = (this.CurrentPosX + this.Width) + MovePatterns[MovePatternCt].FieldsOfView[_FieldOfViewCT].Circles[0].OffsetX;
                            _FieldOfViewRect1[1] = (this.CurrentPosY - _FieldOfViewRect1[3]) + MovePatterns[MovePatternCt].FieldsOfView[_FieldOfViewCT].Circles[0].OffsetY;

                            #endregion

                            #region rectangle 2
                            _FieldOfViewRect2[0] = (_FieldOfViewRect1[0] + _FieldOfViewRect1[2]) - MovePatterns[MovePatternCt].FieldsOfView[_FieldOfViewCT].Circles[1].OffsetX;
                            _FieldOfViewRect2[1] = (_FieldOfViewRect1[1] - _FieldOfViewRect2[3]) - MovePatterns[MovePatternCt].FieldsOfView[_FieldOfViewCT].Circles[1].OffsetY;

                            #endregion


                            #region rectangle 3
                            _FieldOfViewRect3[0] = (_FieldOfViewRect2[0] + _FieldOfViewRect2[2]) - MovePatterns[MovePatternCt].FieldsOfView[_FieldOfViewCT].Circles[2].OffsetX;
                            _FieldOfViewRect3[1] = (_FieldOfViewRect2[1] - _FieldOfViewRect3[3]) - MovePatterns[MovePatternCt].FieldsOfView[_FieldOfViewCT].Circles[2].OffsetY;

                            #endregion

                            #endregion

                            break;
                        }
                    case Util.Helpers.PublicEnums.FieldOfViewDirection.CrossUpLeft:
                        {
                            //first, update X,Y coordinates of 3 field of view rectangles
                            #region CROSS UP LEFT

                            #region rectangle 1

                            _FieldOfViewRect1[0] = (this.CurrentPosX - _FieldOfViewRect1[2]) + MovePatterns[MovePatternCt].FieldsOfView[_FieldOfViewCT].Circles[0].OffsetX;
                            _FieldOfViewRect1[1] = (this.CurrentPosY - _FieldOfViewRect1[3]) + MovePatterns[MovePatternCt].FieldsOfView[_FieldOfViewCT].Circles[0].OffsetY;

                            #endregion

                            #region rectangle 2
                            _FieldOfViewRect2[0] = (_FieldOfViewRect1[0] - _FieldOfViewRect2[2]) + MovePatterns[MovePatternCt].FieldsOfView[_FieldOfViewCT].Circles[1].OffsetX;
                            _FieldOfViewRect2[1] = (_FieldOfViewRect1[1] - _FieldOfViewRect2[3]) - MovePatterns[MovePatternCt].FieldsOfView[_FieldOfViewCT].Circles[1].OffsetY;

                            #endregion

                            #region rectangle 3
                            _FieldOfViewRect3[0] = (_FieldOfViewRect2[0] - _FieldOfViewRect3[2]) + MovePatterns[MovePatternCt].FieldsOfView[_FieldOfViewCT].Circles[2].OffsetX;
                            _FieldOfViewRect3[1] = (_FieldOfViewRect2[1] - _FieldOfViewRect3[3]) - MovePatterns[MovePatternCt].FieldsOfView[_FieldOfViewCT].Circles[2].OffsetY;

                            #endregion

                            #endregion

                            break;
                        }
                    case Util.Helpers.PublicEnums.FieldOfViewDirection.Up:
                        {
                            //first, update X,Y coordinates of 3 field of view rectangles
                            #region UP

                            #region rectangle 1

                            _FieldOfViewRect1[0]= this.CurrentPosX - (this.Width / 2) - MovePatterns[MovePatternCt].FieldsOfView[_FieldOfViewCT].Circles[0].OffsetX;
                            _FieldOfViewRect1[1] = (this.CurrentPosY - _FieldOfViewRect1[3]) - MovePatterns[MovePatternCt].FieldsOfView[_FieldOfViewCT].Circles[0].OffsetY;

                            #endregion

                            #region rectangle 2
                            _FieldOfViewRect2[0] = _FieldOfViewRect1[0] + (_FieldOfViewRect1[2] / 2) - MovePatterns[MovePatternCt].FieldsOfView[_FieldOfViewCT].Circles[1].OffsetX;
                            _FieldOfViewRect2[1] = (_FieldOfViewRect1[1] - _FieldOfViewRect2[3]) - MovePatterns[MovePatternCt].FieldsOfView[_FieldOfViewCT].Circles[1].OffsetY;

                            #endregion

                            #region rectangle 3
                            _FieldOfViewRect3[0] = _FieldOfViewRect2[0]+ (_FieldOfViewRect2[2] / 2) - MovePatterns[MovePatternCt].FieldsOfView[_FieldOfViewCT].Circles[2].OffsetX;
                            _FieldOfViewRect3[1] = (_FieldOfViewRect2[1] - _FieldOfViewRect3[3]) - MovePatterns[MovePatternCt].FieldsOfView[_FieldOfViewCT].Circles[2].OffsetY;

                            #endregion

                            #endregion

                            break;
                        }
                    case Util.Helpers.PublicEnums.FieldOfViewDirection.Down:
                        {
                            //first, update X,Y coordinates of 3 field of view rectangles
                            #region DOWN

                            #region rectangle 1

                            _FieldOfViewRect1[0]= this.CurrentPosX - (this.Width / 2) - MovePatterns[MovePatternCt].FieldsOfView[_FieldOfViewCT].Circles[0].OffsetX;
                            _FieldOfViewRect1[1] = (this.CurrentPosY + this.Height) - MovePatterns[MovePatternCt].FieldsOfView[_FieldOfViewCT].Circles[0].OffsetY;

                            #endregion

                            #region rectangle 2
                            _FieldOfViewRect2[0] = _FieldOfViewRect1[0] + (_FieldOfViewRect1[2] / 2) - MovePatterns[MovePatternCt].FieldsOfView[_FieldOfViewCT].Circles[1].OffsetX;
                            _FieldOfViewRect2[1] = _FieldOfViewRect1[1] + _FieldOfViewRect1[3] - MovePatterns[MovePatternCt].FieldsOfView[_FieldOfViewCT].Circles[1].OffsetY;

                            #endregion

                            #region rectangle 3
                            _FieldOfViewRect3[0] = _FieldOfViewRect2[0] + (_FieldOfViewRect2[2] / 2) - MovePatterns[MovePatternCt].FieldsOfView[_FieldOfViewCT].Circles[2].OffsetX;
                            _FieldOfViewRect3[1] = _FieldOfViewRect2[1] + _FieldOfViewRect2[3] - MovePatterns[MovePatternCt].FieldsOfView[_FieldOfViewCT].Circles[2].OffsetY;

                            #endregion

                            #endregion

                            break;
                        }


                        


                }

           

                #endregion

              

            }
            catch (Exception ex)
            {
                Util.ErrorLogging.LogError(ex);
                return;
            }
        }


        /// <summary>
        /// Draw field of view
        /// </summary>
        private void _DrawFieldOfView()
        {
            

            try
            {
               


                //do not draw field of view if avatar
                //is spotted
                if (_AvatarSpotted || MovePatterns[MovePatternCt].FieldsOfView.Count==0)
                {
                    _DetectAvatar();
                    return;
                }

                if (MovePatternCt <= MovePatterns.Count - 1)
                {

                   
                    //draw!
                        //BUT if NPC is currently attacking, then do not draw visually FOV
                        if (!_IsHeatCooling)
                        {
                            if (this.CurrentState != Util.Helpers.PublicEnums.NPCState.Attacking)
                            {
                                //set texture
                                if (!_CircleTextureSet)
                                {
                                    _CircleTexture = Util.Cache.GetTexture("circleView").Text2D;
                                }

                                Util.Cache.Draw(_CircleTexture, _FieldOfViewRect1, Color.White);
                                Util.Cache.Draw(_CircleTexture, _FieldOfViewRect2, Color.White);
                                Util.Cache.Draw(_CircleTexture, _FieldOfViewRect3, Color.White);
                            }
                        }
                        else
                        {
                            //heat is cooling
                            //draw FOV circles one by one before patrol is resumed
                            if (_DrawCircle1)
                            {
                                Util.Cache.Draw(_CircleTexture, _FieldOfViewRect1, Color.White);

                                if (!_Circle1Drawn)
                                {
                                    _Circle1Drawn = true;
                                    _ElapsedMs4 = Cache.GameTime.TotalGameTime.TotalMilliseconds;
                                }
                            }

                            if (_DrawCircle2)
                            {
                                Util.Cache.Draw(_CircleTexture, _FieldOfViewRect2, Color.White);

                                if (!_Circle2Drawn)
                                {
                                    _Circle2Drawn = true;
                                    _ElapsedMs4 = Cache.GameTime.TotalGameTime.TotalMilliseconds;
                                }
                            }

                            if (_DrawCircle3)
                            {
                                Util.Cache.Draw(_CircleTexture, _FieldOfViewRect3, Color.White);

                                if (!_Circle3Drawn)
                                {
                                    _Circle3Drawn = true;
                                    _ElapsedMs4 = Cache.GameTime.TotalGameTime.TotalMilliseconds;
                                }
                            }
                        }

                    //detext avatar now the FOV is drawn
                        _DetectAvatar();
                    }
                

            }
            catch (Exception ex)
            {
                Util.ErrorLogging.LogError(ex);
                return;
            }
        }


        /// <summary>
        /// update move pattern
        /// ->change to the next move pattern if any
        /// ->or restart to the first move pattern
        /// </summary>
        private void _UpdateMovePattern()
        {
            try
            {
                
                //only if Y and X are reached
                if (!_XReached || !_YReached)
                {
                    return;
                }

                if (MovePatternCt + 1 > MovePatterns.Count - 1)
                {
                    MovePatternCt = 0;

                    //if avatar is not moving, then do not reset field of view ct
                    if (MovePatterns[MovePatternCt].IsMoving)
                    {
                        _FieldOfViewCT = 0;
                    }

                    //reset position
                    CurrentPosX = MovePatterns[MovePatternCt].StartX;
                    CurrentPosY = MovePatterns[MovePatternCt].StartY;
                    //reset flags
                    _XReached = false;
                    _YReached = false;

                }
                else
                {
                    MovePatternCt += 1;

                    //if avatar is not moving, then do not reset field of view ct
                    if (MovePatterns[MovePatternCt].IsMoving)
                    {
                        _FieldOfViewCT = 0;
                    }


                    //reset flags
                    _XReached = false;
                    _YReached = false;
                }




                //determine fov direction
                MovePatterns[MovePatternCt].FieldsOfView[_FieldOfViewCT].DetermineFOVDirection();
                _PrepareFieldOfView();


            }
            catch (Exception ex)
            {
                Util.ErrorLogging.LogError(ex);
                return;
            }
        }

        #endregion



        #endregion



    }
}
